#include "stdafx.h"
#include "VisualHelperManager.h"

namespace Renderer
{
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------

	//class VisualHelperManager : public Renderable
	VisualHelperManager::VisualHelperManager(D3DRenderer& _rRenderer)
	:	Renderable(),
		m_mGrids(),
		m_rRenderer(_rRenderer),
		m_pOrbitVertexDecl(NULL)
	{
		D3DXMatrixIdentity( &m_oWorld );

		D3DVERTEXELEMENT9 aVertexElement[] =
		{
			{	0,	0,	D3DDECLTYPE_FLOAT3,	D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
			D3DDECL_END()
		};
		m_rRenderer.GetDevice()->CreateVertexDeclaration( aVertexElement, &m_pOrbitVertexDecl );
	}

	VisualHelperManager::~VisualHelperManager()
	{
		if ( NULL != m_pOrbitVertexDecl )
		{
			m_pOrbitVertexDecl->Release();
			m_pOrbitVertexDecl = NULL;
		}
	}

	void VisualHelperManager::Render()
	{
		HRESULT hResult = m_rRenderer.GetDevice()->SetVertexDeclaration( m_pOrbitVertexDecl );
		if ( SUCCEEDED( hResult) )
		{
			OrbitInfoMap::iterator iPair = m_mOrbits.begin();
			OrbitInfoMap::iterator iEnd = m_mOrbits.end();
			while ( iEnd != iPair )
			{
				iPair->second.Render( m_rRenderer );
				++iPair;
			}
		}
	}

	const Matrix& VisualHelperManager::GetWorldTransform() const
	{
		return m_oWorld;
	}

	void VisualHelperManager::AddGrid(const string& _strName, const Matrix& _oPlane, const float& _fRepeatFactor)
	{
		GridInfo oInfo;
		DataKey Key = 0;
		MakeKey( Key, _strName );
		m_mGrids[Key] = oInfo;
		GridInfo& rInfo = m_mGrids[Key];
		rInfo.m_fRepeatFactor = _fRepeatFactor;
		rInfo.m_oPlane = _oPlane;
	}

	void VisualHelperManager::RemoveGrid(const string& _strName)
	{
		DataKey Key = 0;
		MakeKey( Key, _strName );
		GridInfoMap::iterator iPair = m_mGrids.find( Key );
		if ( m_mGrids.end() != iPair )
		{
			m_mGrids.erase( iPair );
		}
	}

	void VisualHelperManager::AddOrbit(const string& _strName, const float& _fLength)
	{
		OrbitInfo oInfo;
		DataKey Key = 0;
		MakeKey( Key, _strName );
		OrbitInfoMap::iterator iPair = m_mOrbits.find( Key );
		if ( m_mOrbits.end() == iPair )
		{
			m_mOrbits[Key] = oInfo;
			OrbitInfo& rInfo = m_mOrbits[Key];
			if ( false == rInfo.Create( _fLength, m_rRenderer ) )
			{
				RemoveOrbit( _strName );
			}
		}
	}

	void VisualHelperManager::RemoveOrbit(const string& _strName)
	{
		DataKey Key = 0;
		MakeKey( Key, _strName );
		OrbitInfoMap::iterator iPair = m_mOrbits.find( Key );
		if ( m_mOrbits.end() != iPair )
		{
			iPair->second.Release();
			m_mOrbits.erase( iPair );
		}
	}

	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------

	VisualHelperManager::GridInfo::GridInfo()
	:	m_pVertexBuffer(NULL)
	{

	}

	bool VisualHelperManager::GridInfo::Create(const float& _fRepeatFactor, D3DRenderer& _rRenderer)
	{
		return false;
	}

	void VisualHelperManager::GridInfo::Release()
	{

	}

	void VisualHelperManager::GridInfo::Render(D3DRenderer& _rRenderer)
	{
	}

	//--------------------------------------------------------------------
	//--------------------------------------------------------------------
	//--------------------------------------------------------------------

	VisualHelperManager::OrbitInfo::OrbitInfo()
	:	m_pVertexBuffer(NULL)
	{

	}

	bool VisualHelperManager::OrbitInfo::Create(const float& _fLength, D3DRenderer& _rRenderer)
	{
		float* pfVertices = new float[3 * (c_PointCount + 1)];
		const unsigned int uBufferSize = (c_PointCount + 1) * 3 * sizeof( float );
		const float fAngleStep = ( D3DX_PI * 2 ) / ( c_PointCount - 1 );

		float* pfVertex = pfVertices;
		pfVertex[0] = pfVertex[1] = pfVertex[2] = 0.0f;
		pfVertex += 3;

		for ( unsigned int uIndex = 0 ; c_PointCount > uIndex ; ++uIndex, pfVertex += 3 )
		{
			const float fAngle = uIndex * fAngleStep;
			pfVertex[0] = cos( fAngle ) * _fLength;
			pfVertex[1] = 0.0f;
			pfVertex[2] = sin( fAngle ) * _fLength;
		}

		pfVertex = &pfVertices[3 * c_PointCount];
		pfVertex[0] = pfVertices[3];
		pfVertex[1] = pfVertices[4];
		pfVertex[2] = pfVertices[5];

		HRESULT hResult = _rRenderer.GetDevice()->CreateVertexBuffer( uBufferSize,
			D3DUSAGE_WRITEONLY,
			0,
			D3DPOOL_MANAGED,
			&m_pVertexBuffer,
			NULL);
		if ( FAILED( hResult) )
		{
			return false;
		}

		void* pLockedBuffer = NULL;
		hResult = m_pVertexBuffer->Lock( 0, 0, &pLockedBuffer, D3DLOCK_DISCARD );
		if ( FAILED( hResult) )
		{
			return false;
		}
		memcpy( pLockedBuffer, pfVertices, uBufferSize );
		m_pVertexBuffer->Unlock();

		delete[] pfVertices;

		return true;
	}

	void VisualHelperManager::OrbitInfo::Release()
	{
		if ( NULL != m_pVertexBuffer )
		{
			m_pVertexBuffer->Release();
			m_pVertexBuffer = NULL;
		}
	}

	void VisualHelperManager::OrbitInfo::Render(D3DRenderer& _rRenderer)
	{
		_rRenderer.GetDevice()->SetStreamSource( 0, m_pVertexBuffer, 0, 3 * sizeof( float ) );
		_rRenderer.GetDevice()->DrawPrimitive( D3DPT_LINESTRIP, 0, c_PointCount );
	}

}
